/**
    Copyright 2015 Table Rider
    By: Christoffer Lindström & Daniel Westerlund
*/

#include "ComServer.h"

ComServer::ComServer(){

}
ComServer::~ComServer(){
}
/**
Description:
    Creates a socket with ip ip, and port portnumber.
    Initializes a server and binds the socket.
Pre-condition:
    ip is a valid ip adress, portnumber is a valid port.
Post-condition:
    Server is established with ip and portnumber.
Return:
    A string containing information, error or success.
Test cases:        printf("Getting distance...\n");
        serialport_writebyte(fd, 3);
1. Function call with valid ip (127.0.0.1) and port (4444) => server created with ip and port.
2. Function call with unreachable ip (128.1.2.3) => returns "bind error".
3. Function call with invalid port (80)=> returns "bind error".
4.
5.
*/
const char* ComServer::init(const char* ip, int portnumber)
{
    //if ip is NULL it gets an INADDR_ANY, else it will get the designated ip adress
    if(ip!='\0')
    {
        ipnumber = inet_addr(ip);
    }
    else
    {
         ipnumber = INADDR_ANY;
    }
    port = portnumber;

    #ifdef _WIN32
    WSADATA wsa;
    if(WSAStartup(MAKEWORD(2,2),&wsa)!= 0)//Initialize Winsock-socket
    {
        return "Winsocket init failed\n\0";
    }
    if((ComSocket = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)//Creates Winsock-socket
    {
        return "Could not create socket\n\0";
    }
    #endif

    #ifdef __linux__
    ComSocket = socket(AF_INET , SOCK_STREAM , 0);
    if (ComSocket == -1)//Creates Unix-socket
    {
        return "Unixsocket unit failed\n\0";
    }
    #endif

    //Sets the parameters for the server which is a "struct" inside the socketclass both Winsock and Unix
    server.sin_addr.s_addr = ipnumber;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);

    //Bind
    #ifdef _WIN32
    if(bind(ComSocket,(struct sockaddr*)&server , sizeof(server)) == SOCKET_ERROR)//Binds the Winsock-socket to the designated port
    {
        return "Bind error\n\0";
    }
    #elif __linux__
    if(bind(ComSocket,(struct sockaddr*)&server , sizeof(server)) == -1)//Binds the Unix-socket to the designated port
    {
        return  "Bind error\n\0";
    }
    #endif
    return "Succeeded in initialize server and binding socket\n\0";
}
/**
Description:
    Listens for connections and accept connection from client.
    'queue' connection requests will be queued before further requests are refused.
Pre-condition:
    init function has previously been called and server is running.
Post-condition:
    Client is connected.
Return:
    A string containing information, error or success.
Test cases:
1. Function call (queue=1) before "init" has been called => returns "Could not accept incoming connection"
2.
3.
4.
5.

*/
const char* ComServer::listen_connection()
{
    //Listens a client and it accepts it
    listen(ComSocket, 1);
    c = sizeof(struct sockaddr_in);

    #ifdef _WIN32
    activeSocket = accept(ComSocket, (struct sockaddr *)&client, &c);
    if (activeSocket == INVALID_SOCKET)
    {
        return "Could not accept incoming connection\n\0";
    }
    #elif __linux__
    activeSocket = accept(ComSocket , (struct sockaddr *)&client,(socklen_t*)&c);
    if (activeSocket == -1)
    {
        return "Could not accept incoming connection\n\0";
    }
    #endif
    return "Succeeded in finding and accepting connection\n\0";
}
/**
Description:
    Sends a message using socket.
Pre-condition:
    init and listen_connection has successfully been called.
    message is a message to be sent, length is the length of this message.
Post-condition:
    A message is sent using the socket.
    Prints a message containing information about the error if send fails on win32.
Return:
    -1 if send fail
    0 if send success
Test cases:
1.
2.
3.
4.
5.
*/
int ComServer::send_msg(void* message, int length)
{
    #ifdef __linux__
    if(send(activeSocket , message , length , 0) < 0){
        return -1;
    }
    #elif _WIN32
    if(send(activeSocket , (const char*)message , length, 0) == SOCKET_ERROR)
    {
        printf("send failed: %d\n", WSAGetLastError());
        return -1;
    }
    #endif
    return 0;
}
/**
Description:
    Tries to receive a message using socket.
Pre-condition:
    init and listen_connection has successfully been called.
Post-condition:
    Prints a message containing information about the error if send fails on win32.
Return:
    A string containing information, error or success.
Test cases:
1.
2.
3.
4.
5.
*/
const char* ComServer::receive_msg()
{
    //Makes sure the receive-buffer is empty before receiving
    int i=0;
    while(recv_msg[i] != '\0'){
          recv_msg[i] = '\0';
          i++;
    }
    #ifdef __linux__
    if(recv(activeSocket, recv_msg , 2000 , 0) < 0){
        return '\0';
    }
    #elif _WIN32
    if(recv(activeSocket, recv_msg , 2000 , 0) == SOCKET_ERROR){
        printf("recv failed: %d\n", WSAGetLastError());
        return '\0';
    }
    #endif
    return recv_msg;
}

void ComServer::close_connection()
{
    //Close sockets
    #ifdef __linux__
    close(activeSocket);
    close(ComSocket);
    #elif _WIN32ComSocket
    closesocket(activeSocket);
    closesocket(ComSocket);
    WSACleanup();
    #endif
}
